﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Threading;
using System.Text;
using System.IO;

namespace YYSService
{
    using System.Drawing;
    using System.Drawing.Imaging;
    using System.Net;
    using System.Net.Mail;
    using YYS;
    /// <summary>
    /// 日志缓存处理
    /// </summary>
    public class LogCache
    {
        #region
        /// <summary>
        /// SysLog
        /// </summary>
        public const string SysLog = "SysLog";
        /// <summary>
        /// SysLog\Error
        /// </summary>
        public const string SysLog_Error = @"SysLog\Error";
        /// <summary>
        /// WeiXinApp
        /// </summary>
        public const string WeiXinApp = "WeiXinApp";
        /// <summary>
        /// WeiXinApp\Error
        /// </summary>
        public const string WeiXinApp_Error = @"WeiXinApp\Error";
        /// <summary>
        /// XinTongLog
        /// </summary>
        public const string XinTongLog = "XinTongLog";
        /// <summary>
        /// XinTongLog\Error
        /// </summary>
        public const string XinTongLog_Error = @"XinTongLog\Error";
        /// <summary>
        /// SMSLog
        /// </summary>
        public const string SMSLog = "SMSLog";
        /// <summary>
        /// SMSLog\Error
        /// </summary>
        public const string SMSLog_Error = @"SMSLog\Error";
        /// <summary>
        /// EintLog
        /// </summary>
        public const string EintLog = "EintLog";
        /// <summary>
        /// EintLog\Error
        /// </summary>
        public const string EintLog_Error = @"EintLog\Error";
        /// <summary>
        /// Msg
        /// </summary>
        public const string Msg = "Msg";
        /// <summary>
        /// Msg\Error
        /// </summary>
        public const string Msg_Error = @"Msg\Error";
        /// <summary>
        /// ATT
        /// </summary>
        public const string ATT = "ATT";
        /// <summary>
        /// ATT\Error
        /// </summary>
        public const string ATT_Error = @"ATT\Error";
        /// <summary>
        /// BaseLog\Error
        /// </summary>
        public const string BaseLog_Error = @"BaseLog\Error";
        /// <summary>
        /// ClientLog
        /// </summary>
        public const string ClientLog = "ClientLog";
        /// <summary>
        /// ClientLog\Error
        /// </summary>
        public const string ClientLog_Error = @"ClientLog\Error";
        /// <summary>
        /// oneCardControlerLog
        /// </summary>
        public const string oneCardControlerLog = "oneCardControlerLog";
        /// <summary>
        /// ThirdControllerLog
        /// </summary>
        public const string ThirdControllerLog = @"ThirdControllerLog";
        #endregion

        string _Key = YYS.DefaultValue.IsSvcDebug ? "" : "_" + Guid.NewGuid().ToString("n").Substring(0, 8);
        public string Key { get { return _Key; } }

        private class Nested
        {
            internal static readonly LogCache _Instance = null;
            static Nested() { _Instance = new LogCache(); }
        }
        public static LogCache Instance { get { return Nested._Instance; } }

        System.Collections.Concurrent.ConcurrentQueue<LogData> queue = new System.Collections.Concurrent.ConcurrentQueue<LogData>();
        ManualResetEvent allDone = new ManualResetEvent(false);

        string createLogName(string fileName, string key, int index)
        {
            key = (key ?? string.Empty).Trim();
            index = index < 0 ? 0 : index;
            return fileName.Substring(0, fileName.LastIndexOf("."))
                + (key.Length > 0 ? "_" + key : "")
                + (index > 0 ? "_" + index : "")
                + fileName.Substring(fileName.LastIndexOf("."));
        }

        System.Threading.Tasks.Task logTask;
        private LogCache()
        {
            logTask = System.Threading.Tasks.Task.Factory.StartNew(() =>
            {
                while (true)
                {
                    allDone.Reset();
                    LogData log = null;
                    while ((log = RemoveQueue()) != null)
                    {
                        var title = "异常错误信息【" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "】";
                        try
                        {
                            //创建路径
                            if (!System.IO.Directory.Exists(log.logDir))
                            {
                                System.IO.Directory.CreateDirectory(log.logDir);
                            }
                            //删除3天前的文件
                            try
                            {
                                DirectoryInfo dirInfo = new DirectoryInfo(log.logDir);
                                foreach (var file in dirInfo.EnumerateFiles().Where(f => f.LastWriteTime < DateTime.Now.AddDays(-3)))
                                {
                                    file.Delete();
                                }
                            }
                            catch { }

                            var fileName = log.logDir + createLogName(log.logName, this.Key, 0);
                            //单个文件最大2M
                            var i = 1;
                            while (System.IO.File.Exists(fileName))
                            {
                                FileInfo file = new FileInfo(fileName);
                                if (file.Length >= 2 * 1024 * 1024)
                                {
                                    fileName = log.logDir + createLogName(log.logName, this.Key, i);
                                }
                                else
                                {
                                    break;
                                }
                                i++;
                            }
                            //追加写入文件
                            using (System.IO.StreamWriter streamWriter = new System.IO.StreamWriter(fileName, true, System.Text.Encoding.UTF8))
                            {
                                streamWriter.WriteLine(log.log);
                            }
                            if (fileName.IndexOf("error", StringComparison.OrdinalIgnoreCase) > -1)
                            {
                                YYS.Utility.SendHXTMail("3121527784@qq.com", title, log.log, false);
                            }
                        }
                        catch (Exception ex)
                        {
                            YYS.Utility.SendHXTMail("3121527784@qq.com", title, log.log + System.Environment.NewLine + "日志错误：" + ex.Message, false);
                        }
                    }

                    try
                    {
                        var filePath = Xcode.API.xHostPath("~/REST/");
                        if (System.IO.Directory.Exists(filePath))
                        {
                            var dir = new System.IO.DirectoryInfo(filePath);
                            var list = dir.EnumerateFiles().Where(x => x.LastWriteTime < DateTime.Now.AddHours(-6) && x.Extension == ".htm").ToList();
                            for (var i = list.Count - 1; i >= 0; i--)
                            {
                                list[i].Delete();
                            }
                            list = null;
                        }
                    }
                    catch { }


                    allDone.WaitOne(5 * 60 * 1000);
                }
            });
        }

        void logToDb(LogData log)
        {
            var db = Helper.GETdbHelper(YYS.dbHelper.EnumServer.Local, YYS.dbHelper.ExecType.Exec, DefaultValue.DataBase);
            db.CmdText = "INSERT INTO dbo.T_S_Log (FxL_Detail,FdL_Time) VALUES(@FxL_Detail,GETDATE())";
            db.AddParameter("@FxL_Detail", System.Data.SqlDbType.VarChar, log.jConvertObjectToJson(), -1);
            db.Exec();
        }
        
        public void ConvertFileToImage(string logPath,string imagePath)
        {
            // 确保文件存在
            if (!File.Exists(logPath))
            {
                var log = new YYS.LogModel("YYSService", "ConvertFileToImage", "LogCache.cs", "文件未找到");
                Helper.Log(log);
            }
            string logContent = File.ReadAllText(logPath);

            using (Bitmap image = new Bitmap(1, 1))
            using (Graphics graphics = Graphics.FromImage(image))
            using (Font font = new Font("Arial", 12))
            {
                // 计算文本大小
                int width = (int)graphics.MeasureString(logContent, font).Width;
                int height = (int)graphics.MeasureString(logContent, font).Height;

                // 创建正确大小的图片
                using (Bitmap bmp = new Bitmap(image, new Size(1000, height)))
                using (Graphics g = Graphics.FromImage(bmp))
                {
                    g.Clear(Color.White);
                    g.DrawString(logContent, font, Brushes.Black, 0, 0);
                    bmp.Save(imagePath, System.Drawing.Imaging.ImageFormat.Png);
                }
            }    
        }
        public class fileList
        {
            public string filePath { get; set; }
        }
        public void AddQueue(LogData log)
        {
            queue.Enqueue(log);
            logToDb(log);            
            //截图
            //var filePath = log.logDir + DateTime.Now.ToString("yyyyMMddHH") + ".png";
            //ConvertFileToImage(log.logDir + log.logName, filePath);
            //var list = new List<fileList>();
            //list.Add(new fileList
            //{
            //    filePath = log.logDir + log.logName
            //});
            //list.Add(new fileList{
            //    filePath= filePath
            //});
            //发送邮件给我
            SendEmail(DefaultValue.QQ_Email, "系统错误日志", log.jConvertObjectToJson(), log.logDir + log.logName);
            allDone.Set();
        }
        public string SendEmail(string toEmail,string title,string body,string filePath)
        {
            string Result = null;
            //WYfk8Hsn3jkJ2nZD
            string fromEmail = DefaultValue.QQ_Email;
            string password = DefaultValue.QQ_SMTP;
            if (toEmail.Length <= 0)
            {
                return "邮件地址为空";
            }
            try
            {
                // 创建邮件消息
                // 创建邮件对象
                MailMessage mail = new MailMessage();
                mail.From = new MailAddress(fromEmail, "小杨");
                mail.To.Add(new MailAddress(toEmail));
                mail.Subject = title;
                mail.Body = body;

                // 添加附件
                if (!string.IsNullOrWhiteSpace(filePath))
                {
                    if (File.Exists(filePath))//文件存在
                    {
                        Attachment attachment = new Attachment(filePath);
                        mail.Attachments.Add(attachment);
                    };
                    
                };

                // 创建SMTP客户端
                SmtpClient smtpClient = new SmtpClient("smtp.qq.com", 587);
                smtpClient.Credentials = new NetworkCredential(fromEmail, password);
                smtpClient.EnableSsl = true;

                // 发送邮件
                smtpClient.Send(mail);
            }
            catch (Exception ex)
            {
                var log = new YYS.LogModel("YYSService", "SendEmail", "LogCache.cs", "邮件发送失败");
                log.Add("dbHelper", ex.Message.ToString());
                Helper.Log(log);
                Result = ex.Message;
            }
            return Result;
        }
        public LogData RemoveQueue()
        {
            LogData log;
            queue.TryDequeue(out log);
            return log;
        }

        #region
        public void saveToLog(HttpRequestBase Request, string dirName, string fileName, string postData = null, string errMsg = null)
        {
            #region
            dirName = (dirName ?? string.Empty).Trim();
            fileName = (fileName ?? string.Empty).Trim();

            if (Request != null && dirName.Length > 0 && fileName.Length > 0)
            {
                Uri Uri = null;
                var HttpMethod = "";
                System.Collections.Specialized.NameValueCollection Headers = null;
                System.Collections.Specialized.NameValueCollection QueryString = null;
                System.Collections.Specialized.NameValueCollection Form = null;
                try
                {
                    HttpMethod = Request.HttpMethod;
                    Uri = Request.Url;
                    Headers = Request.Headers;
                    QueryString = Request.QueryString;
                    Form = Request.Form;
                }
                catch
                {
                    var context = System.Web.HttpContext.Current;
                    if (context != null)
                    {
                        try
                        {
                            HttpMethod = context.Request.HttpMethod;
                            Uri = context.Request.Url;
                            Headers = context.Request.Headers;
                            QueryString = context.Request.QueryString;
                            Form = context.Request.Form;
                        }
                        catch { }
                    }
                }

                Action func = () =>
                {
                    StringBuilder sb = new StringBuilder();
                    sb.AppendFormat("{0} ================", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")).AppendLine();
                    try
                    {
                        sb.AppendFormat("{0}: {1}", HttpMethod, Uri).AppendLine();
                        sb.Append("------------------------").AppendLine();

                        sb.Append("------------------------").AppendLine();

                        sb.Append("Request.Headers").AppendLine().AppendLine();
                        if (Headers != null)
                        {
                            foreach (var o in Headers)
                            {
                                sb.AppendFormat("{0}: {1}", o, Headers[o.ToString()]).AppendLine();
                            }
                        }
                        sb.Append("------------------------").AppendLine();

                        sb.Append("Request.QueryString").AppendLine().AppendLine();
                        if (QueryString != null)
                        {
                            foreach (var o in QueryString)
                            {
                                sb.AppendFormat("{0}: {1}", o, QueryString[o.ToString()]).AppendLine();
                            }
                        }
                        sb.Append("------------------------").AppendLine();

                        sb.Append("Request.Form").AppendLine().AppendLine();
                        if (Form != null)
                        {
                            foreach (var o in Form)
                            {
                                sb.AppendFormat("{0}: {1}", o, Form[o.ToString()]).AppendLine();
                            }
                        }
                        sb.Append("------------------------").AppendLine();
                    }
                    catch (Exception ex)
                    {
                        sb.Append("获取.Request.相关信息错误").AppendLine().AppendLine();
                        sb.AppendFormat("{0}", ex.Message).AppendLine();
                        sb.Append("------------------------").AppendLine();
                    }
                    finally
                    {
                        if ((postData ?? string.Empty).Trim().Length > 0)
                        {
                            sb.Append("postData").AppendLine().AppendLine();
                            sb.Append(postData).AppendLine();
                            sb.Append("------------------------").AppendLine();
                        }

                        if ((errMsg ?? string.Empty).Trim().Length > 0)
                        {
                            sb.Append("errMsg").AppendLine().AppendLine();
                            sb.Append(errMsg).AppendLine();
                            sb.Append("------------------------").AppendLine();
                        }

                        AddQueue(new LogData()
                        {
                            logDir = dirName,
                            logName = fileName,
                            log = sb.ToString()
                        });
                    }
                };
                func.BeginInvoke(ar =>
                {
                    func.EndInvoke(ar);
                }, null);
            }
            #endregion
        }
        public void saveToLog(HttpRequest Request, string dirName, string fileName, string postData = null, string errMsg = null)
        {
            #region
            dirName = (dirName ?? string.Empty).Trim();
            fileName = (fileName ?? string.Empty).Trim();

            if (Request != null && dirName.Length > 0 && fileName.Length > 0)
            {
                Uri Uri = null;
                var HttpMethod = "";
                System.Collections.Specialized.NameValueCollection Headers = null;
                System.Collections.Specialized.NameValueCollection QueryString = null;
                System.Collections.Specialized.NameValueCollection Form = null;
                try
                {
                    HttpMethod = Request.HttpMethod;
                    Uri = Request.Url;
                    Headers = Request.Headers;
                    QueryString = Request.QueryString;
                    Form = Request.Form;
                }
                catch
                {
                    var context = System.Web.HttpContext.Current;
                    if (context != null)
                    {
                        try
                        {
                            HttpMethod = context.Request.HttpMethod;
                            Uri = context.Request.Url;
                            Headers = context.Request.Headers;
                            QueryString = context.Request.QueryString;
                            Form = context.Request.Form;
                        }
                        catch { }
                    }
                }

                Action func = () =>
                {
                    StringBuilder sb = new StringBuilder();
                    sb.AppendFormat("{0} ================", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")).AppendLine();
                    try
                    {
                        sb.AppendFormat("{0}: {1}", HttpMethod, Uri).AppendLine();
                        sb.Append("------------------------").AppendLine();

                        sb.Append("------------------------").AppendLine();

                        sb.Append("Request.Headers").AppendLine().AppendLine();
                        if (Headers != null)
                        {
                            foreach (var o in Headers)
                            {
                                sb.AppendFormat("{0}: {1}", o, Headers[o.ToString()]).AppendLine();
                            }
                        }
                        sb.Append("------------------------").AppendLine();

                        sb.Append("Request.QueryString").AppendLine().AppendLine();
                        if (QueryString != null)
                        {
                            foreach (var o in QueryString)
                            {
                                sb.AppendFormat("{0}: {1}", o, QueryString[o.ToString()]).AppendLine();
                            }
                        }
                        sb.Append("------------------------").AppendLine();

                        sb.Append("Request.Form").AppendLine().AppendLine();
                        if (Form != null)
                        {
                            foreach (var o in Form)
                            {
                                sb.AppendFormat("{0}: {1}", o, Form[o.ToString()]).AppendLine();
                            }
                        }
                        sb.Append("------------------------").AppendLine();
                    }
                    catch (Exception ex)
                    {
                        sb.Append("获取.Request.相关信息错误").AppendLine().AppendLine();
                        sb.AppendFormat("{0}", ex.Message).AppendLine();
                        sb.Append("------------------------").AppendLine();
                    }
                    finally
                    {
                        if ((postData ?? string.Empty).Trim().Length > 0)
                        {
                            sb.Append("postData").AppendLine().AppendLine();
                            sb.Append(postData).AppendLine();
                            sb.Append("------------------------").AppendLine();
                        }

                        if ((errMsg ?? string.Empty).Trim().Length > 0)
                        {
                            sb.Append("errMsg").AppendLine().AppendLine();
                            sb.Append(errMsg).AppendLine();
                            sb.Append("------------------------").AppendLine();
                        }

                        AddQueue(new LogData()
                        {
                            logDir = dirName,
                            logName = fileName,
                            log = sb.ToString()
                        });
                    }
                };
                func.BeginInvoke(ar =>
                {
                    func.EndInvoke(ar);
                }, null);
            }
            #endregion
        }
        #endregion
    }

    public class LogData
    {
        public string logDir { get; set; }
        public string logName { get; set; }
        public string log { get; set; }
        public string detail { get; set; }
    }
}